package lambda.lj1;

import org.junit.Test;

import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.averagingInt;

/**
 * @file:
 * @version:
 * @Description: Stream 要组合使用才会发挥更大的功能，链式调用很迷人，根据自己的业务
 * @author: 李津
 * @date: 2021-05-07 16:01
 * 本代码要注意的事项、备注事项等
 */


public class stream2 {

    /**
     * 3.1 转换成值
     * 收集器，一种通用的、从流生成复杂值的结构。只要将它传给 collect 方法，所有的流就都可以使用它了。
     * 标准类库已经提供了一些有用的收集器，以下示例代码中的收集器都是从 java.util.stream.Collectors 类中静态导入的。
     */
    @Test
    public void CollectorsTest(){
        Set<Student> students = new LinkedHashSet<>(3);
        students.add(new Student("路飞",21,180));
        students.add(new Student("礼金",18,190));
        students.add(new Student("红发",40,170));

        OutstandingClass ost1 = new OutstandingClass("一班",students);
        //复制students1，并移除一个学生
        Set<Student> students1 = new LinkedHashSet<>(students);
        students1.add(new Student("小飞",51,200));
        OutstandingClass ost2 = new OutstandingClass("二班",students1);

        //将ostClass1、ostClass2转换为Stream
        Stream<OutstandingClass> classStream = Stream.of(ost1,ost2);
        OutstandingClass outstandingClass = biggestGroup(classStream);
        System.out.println("人数最多的班级是："+outstandingClass.getName());

        System.out.println("一班平均年龄是："+averageNumberOfStudent(students));
        System.out.println("二班平均年龄是："+averageNumberOfStudent(students1));

    }

    /**
     * 获取人数最多的班级
     * @param outstandingClassStream
     * @return
     */
    private static OutstandingClass biggestGroup(Stream<OutstandingClass> outstandingClassStream) {
        return outstandingClassStream.max(comparing(ostClass -> ostClass
                .getStudents().size()))
                .orElseGet(OutstandingClass::new);
    }

    /**
     * 计算平均年龄
     * @param students
     * @return
     */
    private static double averageNumberOfStudent(Set<Student> students){
        return students.stream().collect(averagingInt(Student::getAge));
    }


    /**
     * 3.2 转换成块
     * 常用的流操作是将其分解成两个集合，Collectors.partitioningBy 帮我们实现了，接收一个 Predicate 函数式接口。
     */
    @Test
    public void partitioningBy() {
        Set<Student> students = new LinkedHashSet<>(3);
        students.add(new Student("路飞",21,180));
        students.add(new Student("礼金",18,190));
        students.add(new Student("红发",40,170));

//        将示例学生分为会唱歌与不会唱歌的两个集合。
/*        Map<Boolean, List<Student>> listMap = students.stream().collect(
                Collectors.partitioningBy(student -> student.getSpecialities()
                        .contains(SpecialityEnum.SING)));
        System.out.println(listMap);*/
    }

    /**
     * 3.3 数据分组
     * 数据分组是一种更自然的分割数据操作，与将数据分成 ture 和 false 两部分不同，可以使用任意值对数据分组。
     * Collectors.groupingBy 接收一个 Function 做转换。
     */
    @Test
    public void groupingBy() {
        Set<Student> students = new LinkedHashSet<>(3);
        students.add(new Student("路飞",21,180));
        students.add(new Student("礼金",18,190));
        students.add(new Student("红发",40,170));
        //根据学生第一个特长进行分组
        // 省略List<student> students的初始化
/*        Map<SpecialityEnum, List<Student>> listMap =
                students.stream().collect(
                        Collectors.groupingBy(student-> student.getSpecialities().get(0)));
        System.out.println(listMap);*/
    }

    /**
     * 3.4 字符串拼接
     * 如果将所有学生的名字拼接起来，怎么做呢？通常只能创建一个 StringBuilder，循环拼接。
     * 使用 Stream，使用 Collectors.joining() 简单容易。
     */
    @Test
    public void joining(){
        Set<Student> students = new LinkedHashSet<>(3);
        students.add(new Student("路飞",21,180));
        students.add(new Student("礼金",18,190));
        students.add(new Student("红发",40,170));

        /**
         * joining 接收三个参数，第一个是分界符，第二个是前缀符，第三个是结束符。
         * 也可以不传入参数 Collectors.joining()，这样就是直接拼接。
         */
        String names = students.stream().map(Student::getName)
                .collect(Collectors.joining(",","[","]"));
        System.out.println(names);
    }

}
